
{**********************************************************}
{                                                          }
{       dbExpress for Informix extension                   }
{                                                          }
{       Copyright (c) 2001-2006 Luxena Software Company    }
{       http://www.luxena.com                              }
{       e-mail: support@luxena.com                         }
{                                                          }
{**********************************************************}

{$ALIGN 8}

unit DBXInfExt;

interface

{$IFDEF CLR}
  {$DEFINE DOTNET}
{$ENDIF}

uses
{$IFDEF DOTNET}
  System.Runtime.InteropServices, FMTBcd,
{$ENDIF}
{$IFDEF VER180}
  SqlExpr,
{$ENDIF}
  DBXpress;

const
  SQLNOTFOUND                    =    100;
  IFX_SERVER_BUSY                =   -439;
  IFX_ALREADY_IN_TRANSACTION     =   -535;
  IFX_INVALID_TRANSACTION_STATE  =  -1800;

type

{$IFDEF DOTNET}
  [StructLayout(LayoutKind.Sequential, Pack = 8)]
{$ENDIF}
  sqlcaw_s = record
    sqlwarn0: Char; // = W if any of sqlwarn[1-7] = W
    sqlwarn1: Char; // = W if any truncation occurred or database has transactions or no privileges revoked
    sqlwarn2: Char; // = W if a null value returned or ANSI database
    sqlwarn3: Char; // = W if no. in select list != no. in into list or turbo backend or no privileges granted
    sqlwarn4: Char; // = W if no where clause on prepared update, delete or incompatible float format
    sqlwarn5: Char; // = W if non-ANSI statement
    sqlwarn6: Char; // = W if server is in data replication secondary mode
    sqlwarn7: Char; // = W if database locale is different from proc_locale
  end;

{$IFDEF DOTNET}
  [StructLayout(LayoutKind.Sequential, Pack = 8)]
{$ELSE}
  PSQLCA = ^TSQLCA;
{$ENDIF}
  TSQLCA = record
    sqlcode: Integer;
{$IFDEF DOTNET}
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=72)]
{$ENDIF}
    sqlerrm: array[0..71] of Char; // error message parameters
{$IFDEF DOTNET}
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=8)]
{$ENDIF}
    sqlerrp: array[0..7] of Char;
{$IFDEF DOTNET}
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=6)]
{$ENDIF}
    sqlerrd: array[0..5] of Integer;
    // 0 - estimated number of rows returned
    // 1 - serial value after insert or ISAM error code
    // 2 - number of rows processed
    // 3 - estimated cost
    // 4 - offset of the error into the SQL statement
    // 5 - rowid after insert
{$IFDEF DOTNET}
    sqlwarn: sqlcaw_s;
{$ELSE}
    case Integer of
      0: (sqlawarn: array[0..7] of Char);
      1: (sqlwarn: sqlcaw_s);
{$ENDIF}
  end;

{$IFDEF DOTNET}
  TimeOutCallback = procedure (CustomData: IntPtr; Status: Integer);
{$ELSE}
  TimeOutCallback = procedure (CustomData: Pointer; Status: Integer); stdcall;
{$ENDIF}

{$IFDEF DOTNET}

  TInformixConnection = class
  public
    constructor Create(Handle: IntPtr);
    function SQLCA: TSQLCA;
    function ErrorMessage: string;
    function SetTimeOutCallback(TimeOut: Integer; Callback: TimeOutCallback;
      CustomData: IntPtr): SQLResult;
    function InterruptSQL: Boolean;
    // to get the last inserted serial8 value overload appropriative to int8
    // type mapping should be used
    function GetLastInsertedSerial8(out Value: TBcd): Boolean; overload;
    function GetLastInsertedSerial8(out Value: Double): Boolean; overload;
    function ServerVersion: string;
    function IsDynamicServer: Boolean;
    function IsUniversalServer: Integer;
    function SessionID: Integer;
  private
    FHandle: IntPtr;
  end;

  function IInformixConnection(Handle: IntPtr): TInformixConnection;

{$ELSE}

{$IFNDEF VER180}
  ISQLConnectionBase = ISQLConnection;
{$ELSE}
  ISQLConnectionBase = ISQLConnection25;
{$ENDIF}

  TInformixConnection = interface(ISQLConnectionBase)
    function SQLCA: PSQLCA; stdcall;
    function ErrorMessage: PChar; stdcall; overload;
    function SetTimeOutCallback(TimeOut: Integer; Callback: TimeOutCallback;
      CustomData: Pointer): SQLResult; stdcall;
    function InterruptSQL: Boolean; stdcall;
    // writes TBcd or Double value depending from int8 type mapping
    function GetLastInsertedSerial8(out Value): Boolean; stdcall;
    function ServerVersion: PChar; stdcall;
    function IsDynamicServer: Boolean; stdcall;
    function IsUniversalServer: Integer; stdcall;
    function SessionID: Integer; stdcall;
  end;

{$IFNDEF VER180}
  IInformixConnection = TInformixConnection;
{$ELSE}
  function IInformixConnection(SQLConnection: TISQLConnection): TInformixConnection;
{$ENDIF}

{$ENDIF}


implementation

{$IFDEF DOTNET}

[DllImport('DBXInfExtIntf.dll')]
function SQLCA(Self: IntPtr): IntPtr; external;

[DllImport('DBXInfExtIntf.dll')]
function ErrorMessage(Self: IntPtr): string; external;

[DllImport('DBXInfExtIntf.dll')]
function SetTimeOutCallback(Self: IntPtr; TimeOut: Integer;
  Callback: TimeOutCallback; CustomData: IntPtr): SQLResult; external;

[DllImport('DBXInfExtIntf.dll')]
function InterruptSQL(Self: IntPtr): Boolean; external;

type
  TBcdArray = array [0..SizeOfTBcd - 1] of Byte;

[DllImport('DBXInfExtIntf.dll')]
function GetLastInsertedSerial8(Self: IntPtr; [MarshalAs(UnmanagedType.LPArray)] Value: TBcdArray): Boolean; external; overload;

[DllImport('DBXInfExtIntf.dll')]
function GetLastInsertedSerial8(Self: IntPtr; out Value: Double): Boolean; external; overload;

[DllImport('DBXInfExtIntf.dll')]
function ServerVersion(Self: IntPtr): string; external;

[DllImport('DBXInfExtIntf.dll')]
function IsDynamicServer(Self: IntPtr): Boolean; external;

[DllImport('DBXInfExtIntf.dll')]
function IsUniversalServer(Self: IntPtr): Integer; external;

[DllImport('DBXInfExtIntf.dll')]
function SessionID(Self: IntPtr): Integer; external;

{ TInformixConnection }

constructor TInformixConnection.Create(Handle: IntPtr);
begin
  inherited Create;
  FHandle := Handle;
end;

function TInformixConnection.SQLCA: TSQLCA;
begin
  Result := TSQLCA(Marshal.PtrToStructure(DBXInfExt.SQLCA(FHandle), TypeOf(TSQLCA)));
end;

function TInformixConnection.ErrorMessage: string;
begin
  Result := DBXInfExt.ErrorMessage(FHandle);
end;

function TInformixConnection.SetTimeOutCallback(TimeOut: Integer;
  Callback: TimeOutCallback; CustomData: IntPtr): SQLResult;
begin
  Result := DBXInfExt.SetTimeOutCallback(FHandle, TimeOut, Callback, CustomData);
end;

function TInformixConnection.InterruptSQL: Boolean;
begin
  Result := DBXInfExt.InterruptSQL(FHandle);
end;

function TInformixConnection.GetLastInsertedSerial8(out Value: TBcd): Boolean;
var
  ValueArray: TBcdArray;
begin
  Result := DBXInfExt.GetLastInsertedSerial8(FHandle, ValueArray);
  Value := TBcd.FromBytes(ValueArray);
end;

function TInformixConnection.GetLastInsertedSerial8(out Value: Double): Boolean;
begin
  Result := DBXInfExt.GetLastInsertedSerial8(FHandle, Value);
end;

function TInformixConnection.ServerVersion: string;
begin
  Result := DBXInfExt.ServerVersion(FHandle);
end;

function TInformixConnection.IsDynamicServer: Boolean;
begin
  Result := DBXInfExt.IsDynamicServer(FHandle);
end;

function TInformixConnection.IsUniversalServer: Integer;
begin
  Result := DBXInfExt.IsUniversalServer(FHandle);
end;

function TInformixConnection.SessionID: Integer;
begin
  Result := DBXInfExt.SessionID(FHandle);
end;

function IInformixConnection(Handle: IntPtr): TInformixConnection;
begin
  Result := TInformixConnection.Create(Handle);
end;

{$ELSE}

{$IFDEF VER180}

type
  TIISQLConnection = class(TISQLConnection)
  private
    I: TInformixConnection;
  end;

function IInformixConnection(SQLConnection: TISQLConnection): TInformixConnection;
begin
  if SQLConnection <> nil then
    Result := TIISQLConnection(SQLConnection).I else
    Result := nil;
end;

{$ENDIF}

{$ENDIF}


end.
